﻿using System;
using System.Collections.Generic;
using NHibData.SessionManager;
using NHibernate;
using NHibernate.Cfg;
using System.IO;

namespace NHibData.Repository
{
    /// <summary>
    /// Class for managing NHibernate sessions
    /// </summary>
    public sealed class NHibernateHelper
    {
        /// <summary>
        /// Shows where sessions will be stored
        /// </summary>
        public enum ESessionStorage
        {
            /// <summary>
            /// Store sessions in HttpContext
            /// </summary>
            HttpContext,

            /// <summary>
            /// Store sessions in dictionary
            /// </summary>
            Dictionary
        }

        /// <summary>
        /// Shows where sessions will be stored
        /// </summary>
        public static ESessionStorage SessionStorage { get; set; }

        public static IInterceptor Interceptor;

        public static INHibenraneSessionManager HttpContextSessionManager;
        public static INHibenraneSessionManager DictionarySessionManager;

        public static INHibenraneSessionManager NHibernateSessionManager
        {
            get
            {
                if (SessionStorage == ESessionStorage.Dictionary)
                    return DictionarySessionManager;
                return HttpContextSessionManager;
            }
        }


        static NHibernateHelper()
        {
            //By dufault stores sessions in HttpContext
            SessionStorage = ESessionStorage.HttpContext;

            HttpContextSessionManager = new HttpContextSessionManager();
            DictionarySessionManager = new DictionarySessionManager();
        }

        /// <summary>
        /// Key for stored session in HttpContext[...]
        /// </summary>
        public const string DefaultNHibernateConfigName = "_default.cfg.xml";
        //public const string KWNHibernateConfigName = "knowledgeweb.cfg.xml";
        
        /// <summary>
        /// A collection of session factories (a factory for for each DB)
        /// </summary>
        private static readonly IDictionary<string, ISessionFactory> SessionFactories = new Dictionary<string, ISessionFactory>();


        /// <summary>
        /// Get from the dictionaey session factory by key or if factory doesn't exist - create new one 
        /// </summary>
        /// <param name="nHibernareConfigName">key - represented by hibernate config file name</param>
        /// <returns>Session factory</returns>
        private static ISessionFactory GetFactoryByKey(string nHibernareConfigName)
        {            
            // If dictionary already has sessionFactory
            if (SessionFactories.ContainsKey(nHibernareConfigName))
                return SessionFactories[nHibernareConfigName];

            // Otherwise - create new one
            string configPath = Path.Combine(System.Web.HttpContext.Current.Server.MapPath("~/bin"), "Mapping/" + nHibernareConfigName);

            var cfg = new Configuration();
            //cfg.SetInterceptor(Interceptor);
            var sessionFactory = cfg.Configure(configPath).BuildSessionFactory();
            
            //cfg.EventListeners.LoadEventListeners = new ILoadEventListener[] { new NHibernateLoadEventListener(), new DefaultLoadEventListener() };
            //cfg.EventListeners.DeleteEventListeners = new IDeleteEventListener[] { new NHibernateDeleteEventListener(), new DefaultDeleteEventListener() };
            //cfg.EventListeners.SaveEventListeners = new ISaveOrUpdateEventListener[] { new NHibernateSaveOrUpdateEventListener(), new DefaultSaveOrUpdateEventListener() };
            //cfg.EventListeners.UpdateEventListeners = new ISaveOrUpdateEventListener[] { new NHibernateSaveOrUpdateEventListener(), new DefaultSaveOrUpdateEventListener() };

            SessionFactories.Add(nHibernareConfigName, sessionFactory);
            return sessionFactory;
        }


        /// <summary>
        /// Get NHibernateSession from HTTPContext 
        /// </summary>
        /// <returns></returns>
        public static ISession GetCurrentSession()
        {
            return GetCurrentSession(DefaultNHibernateConfigName);            
        }

        /// <summary>
        /// Get from HTTP context current session by key
        /// </summary>
        /// <param name="nHibernareConfigName"></param>
        /// <returns></returns>
        public static ISession GetCurrentSession(string nHibernareConfigName)
        {

            if(string.IsNullOrEmpty(nHibernareConfigName))
                throw new ArgumentNullException("nHibernareConfigName");

            var sessionFactory = GetFactoryByKey(nHibernareConfigName);
            ISession session = NHibernateSessionManager.GetSessionByKey(nHibernareConfigName);

            if (session == null)
            {
                session = sessionFactory.OpenSession();
                NHibernateSessionManager.SetSessionByKey(nHibernareConfigName, session);
            }
            return session;
        }

        /// <summary>
        /// Close current session
        /// </summary>
        public static void CloseSession()
        {
            CloseSession(DefaultNHibernateConfigName);
        }

        /// <summary>
        /// Close session by key
        /// </summary>
        /// <param name="nHibernareConfigName">nHibernateConfig </param>
        public static void CloseSession(string nHibernareConfigName)
        {
            if (string.IsNullOrEmpty(nHibernareConfigName))
                throw new ArgumentNullException("nHibernareConfigName");

            ISession session = NHibernateSessionManager.GetSessionByKey(nHibernareConfigName);
            if (session != null)
            {
                session.Close();
            }
        }  
    }
}